package crontab

import (
	"encoding/json"
	"fmt"
	"github.com/jinzhu/gorm"
	"github.com/robfig/cron/v3"
	"manageCrontab/db"
	"manageCrontab/lib"
	"manageCrontab/lib/localtime"
	"manageCrontab/models"
	"time"
)

var Cront = NewCrontab()

//--------------------------------------------
// Cron表达式几个简单范例：
// 每隔5秒执行一次：*/5 * * * * ?
// 每隔1分钟执行一次：0 */1 * * * ?
// 每天23点执行一次：0 0 23 * * ?
// 每天凌晨1点执行一次：0 0 1 * * ?
// 每月1号凌晨1点执行一次：0 0 1 1 * ?
// 每月最后一天23点执行一次：0 0 23 L * ?
// 每周星期天凌晨1点实行一次：0 0 1 ? * L
// 在26分、29分、33分执行一次：0 26,29,33 * * * ?
// 每天的0点、13点、18点、21点都执行一次：0 0 0,13,18,21 * * ?
//--------------------------------------------
// @title 添加数据
func addData() {
	task := models.Task{}
	task.TaskId = lib.GendXid()
	task.TaskName = "测试用上10 " + lib.DATETIME
	task.TaskDescript = "测试用上10 " + lib.DATETIME
	//Cront.CrontabSpec = "* 10,20 9,18 * * ?"
	task.TaskSpec = "0 */30 * * * ?"
	task.TaskStatus = 0
	task.RunCount = 0
	task.TaskType = "email"
	emailInfo := models.EmailInfo{}
	emailInfo.MailTo = []string{"1138675081@qq.com"}
	emailInfo.Subject = "记得打卡, 30分钟发送一次"
	emailInfo.Body = "记得早上9点晚上18点打卡"
	bson, err := json.Marshal(emailInfo)
	if err != nil {
		panic(err)
	}
	task.TaskData = string(bson)
	db.GetDB().Create(&task)
}

// 添加定时任务
func AddTask(t models.Task, spec string) cron.EntryID {
	if t.TaskType == "run" { // 主要任务
		eid, err := Cront.AddJobByFunc(spec, func() {
			runTask()
		})
		if err != nil {
			panic(err)
		}
		return eid
	}
	if t.TaskType == "test" {
		if Cront.IsExistsJob(t.EntryID) {
			Cront.DelByID(t.EntryID)
		}
		eid, err := Cront.AddJobByFunc(spec, func() {
			// 更新运行次数，最后运行时间
			updateTaskInfo(t.TaskId)
			task_ := models.Task{}
			// 查询任务最新信息
			db.GetDB().Where("task_id=?", t.TaskId).First(&task_)
			fmt.Printf("%s  测试%d次\n", task_.TaskName, task_.RunCount+1)
		})
		if err != nil {
			fmt.Println("错误：" + err.Error())
		}
		return eid
	}
	if t.TaskType == "email" {
		if Cront.IsExistsJob(t.EntryID) {
			Cront.DelByID(t.EntryID)
		}
		eid, err := Cront.AddJobByFunc(spec, func() {
			// 更新运行次数，最后运行时间
			updateTaskInfo(t.TaskId)
			emailInfo := models.EmailInfo{}
			err := json.Unmarshal([]byte(t.TaskData), &emailInfo)
			if err != nil {
				fmt.Println(err.Error())
				return
			}
			lib.SendMail(emailInfo.MailTo, emailInfo.Subject, emailInfo.Body)
			task_ := models.Task{}
			// 查询任务最新信息
			db.GetDB().Where("task_id=?", t.TaskId).First(&task_)
			fmt.Printf("%s  发送邮件%d次\n", task_.TaskName, task_.RunCount+1)

		})
		if err != nil {
			fmt.Println("错误：" + err.Error())
		}
		return eid
	}
	if t.TaskType == "cmd" {
		if Cront.IsExistsJob(t.EntryID) {
			Cront.DelByID(t.EntryID)
		}
		eid, err := Cront.AddJobByFunc(spec, func() {
			// 更新运行次数，最后运行时间
			updateTaskInfo(t.TaskId)
			taskData := make(map[string]interface{})
			err := json.Unmarshal([]byte(t.TaskData), &taskData)
			if err != nil {
				fmt.Println("Json错误：" + err.Error())
				return
			}
			if taskData["dir"] == nil {
				fmt.Println("参数错误：不存在dir参数")
				return
			}
			if taskData["commandName"] == nil {
				fmt.Println("参数错误：不存在commandName参数")
				return
			}
			dir := taskData["dir"].(string)
			commandName := taskData["commandName"].(string)
			param := []string{}
			if taskData["param"] == nil {
				fmt.Println("参数错误：不存在param参数")
				return
			}
			if _, ok := taskData["param"].([]interface{}); !ok {
				fmt.Println("参数错误：param类型错误")
				return
			}
			for _, val := range taskData["param"].([]interface{}) {
				param = append(param, val.(string))
			}
			err = lib.CmdAndChangeDirToShow(dir, commandName, param)
			if err != nil {
				fmt.Println("错误：" + err.Error())
				return
			}
			task_ := models.Task{}
			// 查询任务最新信息
			db.GetDB().Where("task_id=?", t.TaskId).First(&task_)
			fmt.Printf("%s  执行命令%d次\n", task_.TaskName, task_.RunCount+1)
		})
		if err != nil {
			fmt.Println("错误：" + err.Error())
		}
		return eid
	}
	return 0
}

// @title 停止任务根据任务id
// @param ct 任务
// @param updateRunStatus 是否更新数据库run_status
func StopTaskById(t models.Task, updateRunStatus bool) error {
	if Cront.IsExistsJob(t.EntryID) {
		Cront.DelByID(t.EntryID)
	}
	//更新任务状态
	updateData := make(map[string]interface{})
	if updateRunStatus {
		updateData["task_status"] = 2
	}
	updateData["run_count"] = 0
	return db.GetDB().Model(&models.Task{TaskId: t.TaskId}).Updates(updateData).Error
}

// @title 重启，一般是崩了的情况需要调用该方法，把以前的任务重新加进去
func ReStart() {
	tasks := []models.Task{}
	db.GetDB().Where("is_valid=1 and task_status=1").Find(&tasks)
	for _, val := range tasks {
		eid := AddTask(val, val.TaskSpec)
		task_ := models.Task{}
		task_.TaskId = val.TaskId
		fmt.Println(task_)
		taskUpdate := make(map[string]interface{})
		taskUpdate["entry_id"] = eid
		taskUpdate["run_count"] = 0
		db.GetDB().Model(&task_).Updates(taskUpdate)
	}
}

// @title 运行可执行的任务
func runTask() {
	tasks := []models.Task{}
	db.GetDB().Where("is_valid=1 and task_status=0").Find(&tasks)
	for _, val := range tasks {
		eid := AddTask(val, val.TaskSpec)
		task_ := models.Task{}
		task_.TaskId = val.TaskId
		db.GetDB().Model(&task_).Updates(models.Task{TaskStatus: 1, EntryID: eid})
	}
}

// @title 停止任务
func StopTask() {
	count := 0
	fmt.Println("StopTask....")
	for {
		count++
		fmt.Printf("StopTask扫描任务%d次\n", count)
		tasks := []models.Task{}
		db.GetDB().Where("is_valid=1 and task_status=2 and run_count>0").Find(&tasks)
		for _, val := range tasks {
			StopTaskById(val, false)
		}
		time.Sleep(5000 * time.Millisecond)
		//fmt.Println("所有任务id")
		//fmt.Println(Cront.Entries())
	}
}

// @title 更新task任务信息
// @note 以后会更新成功数，失败数等等
func updateTaskInfo(taskId string) {
	db.GetDB().Model(&models.Task{TaskId: taskId}).
		Updates(map[string]interface{}{"run_count": gorm.Expr("run_count + 1"), "run_last_time": localtime.LocalTime{time.Now()}})
}
